﻿using System;
using Is.Test;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Should.Fluent;

namespace Is.Test
{
    [TestClass]
    public partial class IsObjectExtensionsTest
    {
        [TestMethod]
        public void Test_IsGreaterThan()
        {
            1.Is().GreaterThan(1).Should().Be.False();
            2.Is().GreaterThan(1).Should().Be.True();
            1.Is().GreaterThan(2).Should().Be.False();
            DateTime today = DateTime.Today;
            DateTime tomorrow = DateTime.Today.AddDays(1);
            tomorrow.Is().GreaterThan(today).Should().Be.True();
            today.Is().GreaterThan(tomorrow).Should().Be.False();
            today.Is().GreaterThan(today).Should().Be.False();
            "b".Is().GreaterThan("a").Should().Be.True();
            "a".Is().GreaterThan("b").Should().Be.False();
            "a".Is().GreaterThan("a").Should().Be.False();
            "a".Is().GreaterThan("A").Should().Be.False();
            "a".Is().GreaterThan("A", StringComparer.Ordinal).Should().Be.True();
            "a".Is().GreaterThan("A", StringComparer.OrdinalIgnoreCase).Should().Be.False();

            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().GreaterThan(null));
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().GreaterThanOrEqualTo("A", null));

            object nullObject = null;
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => nullObject.Is().GreaterThan("a"));
        }

        [TestMethod]
        public void Test_IsGreaterThanOrEqualTo()
        {
            1.Is().GreaterThanOrEqualTo(1).Should().Be.True();
            2.Is().GreaterThanOrEqualTo(1).Should().Be.True();
            1.Is().GreaterThanOrEqualTo(2).Should().Be.False();
            DateTime today = DateTime.Today;
            DateTime tomorrow = DateTime.Today.AddDays(1);
            tomorrow.Is().GreaterThanOrEqualTo(today).Should().Be.True();
            today.Is().GreaterThanOrEqualTo(tomorrow).Should().Be.False();
            today.Is().GreaterThanOrEqualTo(today).Should().Be.True();
            "b".Is().GreaterThanOrEqualTo("a").Should().Be.True();
            "a".Is().GreaterThanOrEqualTo("b").Should().Be.False();
            "a".Is().GreaterThanOrEqualTo("a").Should().Be.True();
            "a".Is().GreaterThanOrEqualTo("A").Should().Be.False();
            "a".Is().GreaterThanOrEqualTo("A", StringComparer.Ordinal).Should().Be.True();
            "a".Is().GreaterThanOrEqualTo("A", StringComparer.OrdinalIgnoreCase).Should().Be.True();

            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().GreaterThanOrEqualTo(null));
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().GreaterThanOrEqualTo("A", null));

            object nullObject = null;
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => nullObject.Is().GreaterThanOrEqualTo("a"));
        }

        [TestMethod]
        public void Test_IsInRange()
        {
            1.50.Is().InRange(.75, 1.25).Should().Be.False();
            1.0.Is().InRange(.75, 1.25).Should().Be.True();
            0.Is().InRange(1, 2).Should().Be.False();
            1.Is().InRange(2, 3).Should().Be.False();
            2.Is().InRange(0, 1).Should().Be.False();
            2.Is().InRange(1, 3).Should().Be.True();
            "adam".Is().InRange("bob", "scott").Should().Be.False();
            "bob".Is().InRange("adam", "scott").Should().Be.True();
            new ComparableObject(1).Is().InRange(new ComparableObject(0), new ComparableObject(2)).Should().Be.True();
            new ComparableObject(1).Is().InRange(new DerivedComparableObject(0), new DerivedComparableObject(2)).Should().Be.True();
            new DerivedComparableObject(1).Is<ComparableObject>().InRange(new ComparableObject(0), new ComparableObject(2)).Should().Be.True();
            new GenericComparableObject(1).Is().InRange(new GenericComparableObject(0), new GenericComparableObject(2)).Should().Be.True();
            new GenericComparableObject(1).Is().InRange(new DerivedGenericComparableObject(0), new DerivedGenericComparableObject(2)).Should().Be.True();
            new DerivedGenericComparableObject(1).Is<GenericComparableObject>().InRange(new GenericComparableObject(0), new GenericComparableObject(2)).Should().Be.True();
            new ComparableObject(3).Is().InRange(new ComparableObject(0), new ComparableObject(2)).Should().Be.False();
            new GenericComparableObject(3).Is().InRange(new GenericComparableObject(0), new GenericComparableObject(2)).Should().Be.False();
            new ComparableObject(3).Is().InRange(new DerivedComparableObject(0), new DerivedComparableObject(2)).Should().Be.False();
            new GenericComparableObject(3).Is().InRange(new DerivedGenericComparableObject(0), new DerivedGenericComparableObject(2)).Should().Be.False();

            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().InRange(null, "z"));
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().InRange("a", null));
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().InRange("a", "z", null));

            object nullObject = null;
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => nullObject.Is().InRange("a", "z"));
        }

        [TestMethod]
        public void Test_IsNotInRange()
        {
            1.50.Is().Not.InRange(.75, 1.25).Should().Be.True();
            1.0.Is().Not.InRange(.75, 1.25).Should().Be.False();
            0.Is().Not.InRange(1, 2).Should().Be.True();
            1.Is().Not.InRange(2, 3).Should().Be.True();
            2.Is().Not.InRange(0, 1).Should().Be.True();
            2.Is().Not.InRange(1, 3).Should().Be.False();
            "adam".Is().Not.InRange("bob", "scott").Should().Be.True();
            "bob".Is().Not.InRange("adam", "scott").Should().Be.False();
            new ComparableObject(1).Is().Not.InRange(new ComparableObject(0), new ComparableObject(2)).Should().Be.False();
            new ComparableObject(1).Is().Not.InRange(new DerivedComparableObject(0), new DerivedComparableObject(2)).Should().Be.False();
            new DerivedComparableObject(1).Is<ComparableObject>().Not.InRange(new ComparableObject(0), new ComparableObject(2)).Should().Be.False();
            new GenericComparableObject(1).Is().Not.InRange(new GenericComparableObject(0), new GenericComparableObject(2)).Should().Be.False();
            new GenericComparableObject(1).Is().Not.InRange(new DerivedGenericComparableObject(0), new DerivedGenericComparableObject(2)).Should().Be.False();
            new DerivedGenericComparableObject(1).Is<GenericComparableObject>().Not.InRange(new GenericComparableObject(0), new GenericComparableObject(2)).Should().Be.False();
            new ComparableObject(3).Is().Not.InRange(new ComparableObject(0), new ComparableObject(2)).Should().Be.True();
            new GenericComparableObject(3).Is().Not.InRange(new GenericComparableObject(0), new GenericComparableObject(2)).Should().Be.True();
            new ComparableObject(3).Is().Not.InRange(new DerivedComparableObject(0), new DerivedComparableObject(2)).Should().Be.True();
            new GenericComparableObject(3).Is().Not.InRange(new DerivedGenericComparableObject(0), new DerivedGenericComparableObject(2)).Should().Be.True();

            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().Not.InRange(null, "z"));
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().Not.InRange("a", null));
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().Not.InRange("a", "z", null));

            object nullObject = null;
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => nullObject.Is().Not.InRange("a", "z"));
        }

        [TestMethod]
        public void Test_IsLessThan()
        {
            DateTime today = DateTime.Today;
            DateTime tomorrow = DateTime.Today.AddDays(1);

            1.Is().LessThan(2).Should().Be.True();
            2.Is().LessThan(1).Should().Be.False();
            today.Is().LessThan(tomorrow).Should().Be.True(); ;
            tomorrow.Is().LessThan(today).Should().Be.False();
            "a".Is().LessThan("b").Should().Be.True();
            "b".Is().LessThan("a").Should().Be.False();
            "A".Is().LessThan("a", StringComparer.Ordinal).Should().Be.True();
            "A".Is().LessThan("a", StringComparer.OrdinalIgnoreCase).Should().Be.False();

            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().LessThan(null));
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().LessThan("A", null));

            object nullObject = null;
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => nullObject.Is().LessThan("a"));
        }

        [TestMethod]
        public void Test_IsLessThanOrEqualTo()
        {
            1.Is().LessThanOrEqualTo(1).Should().Be.True();
            2.Is().LessThanOrEqualTo(1).Should().Be.False();
            1.Is().LessThanOrEqualTo(2).Should().Be.True();
            DateTime today = DateTime.Today;
            DateTime tomorrow = DateTime.Today.AddDays(1);
            tomorrow.Is().LessThanOrEqualTo(today).Should().Be.False();
            today.Is().LessThanOrEqualTo(tomorrow).Should().Be.True();
            today.Is().LessThanOrEqualTo(today).Should().Be.True();
            "b".Is().LessThanOrEqualTo("a").Should().Be.False();
            "a".Is().LessThanOrEqualTo("b").Should().Be.True();
            "a".Is().LessThanOrEqualTo("a").Should().Be.True();
            "a".Is().LessThanOrEqualTo("A").Should().Be.True();
            "a".Is().LessThanOrEqualTo("A", StringComparer.Ordinal).Should().Be.False();
            "a".Is().LessThanOrEqualTo("A", StringComparer.OrdinalIgnoreCase).Should().Be.True();

            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().LessThanOrEqualTo(null));
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => "a".Is().LessThanOrEqualTo("A", null));

            object nullObject = null;
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => nullObject.Is().LessThanOrEqualTo("a"));
        }

        [TestMethod]
        public void Test_IsNull()
        {
            object nullObject = null;
            nullObject.Is().Null().Should().Be.True();
            "a".Is().Null().Should().Be.False();
            new object().Is().Null().Should().Be.False();
        }

        [TestMethod]
        public void Test_IsNotNull()
        {
            object nullObject = null;
            nullObject.Is().Not.Null().Should().Be.False();
            "a".Is().Not.Null().Should().Be.True();
            new object().Is().Not.Null().Should().Be.True();
        }

        [TestMethod]
        public void Test_IsSameAs()
        {
            int one = 1;
            int anotherone = 1;
            1.Is().SameAs(1).Should().Be.False();
            one.Is().SameAs(anotherone).Should().Be.False();
            one.Is().SameAs(one).Should().Be.False();

            string a = "alma";
            string anothera = "alma";
            "alma".Is().SameAs("alma").Should().Be.True();
            a.Is().SameAs(anothera).Should().Be.True();
            a.Is().SameAs(a).Should().Be.True();
            "alma".Is().SameAs("jkrte").Should().Be.False();

            string actual = "Abc";
            string expected = "a".ToUpperInvariant() + "bc";
            actual.Is().SameAs(expected).Should().Be.False();

            ComparableObject c = new ComparableObject(1);
            ComparableObject anotherc = new ComparableObject(1);
            c.Is().SameAs(c).Should().Be.True();
            c.Is().SameAs(anotherc).Should().Be.False();

            object nullObject = null;
            nullObject.Is().SameAs(1).Should().Be.False();
            nullObject.Is().SameAs("a").Should().Be.False();
            nullObject.Is().SameAs(c).Should().Be.False();
            nullObject.Is().SameAs(nullObject).Should().Be.True();
            c = null;
            nullObject.Is().SameAs(c).Should().Be.True();
            anotherc = null;
            anotherc.Is().SameAs(c).Should().Be.True();
            c.Is().SameAs(anotherc).Should().Be.True();
        }

        [TestMethod]
        public void Test_IsNotSameAs()
        {
            int one = 1;
            int anotherone = 1;
            1.Is().Not.SameAs(1).Should().Be.True();
            one.Is().Not.SameAs(anotherone).Should().Be.True();
            one.Is().Not.SameAs(one).Should().Be.True();

            string a = "alma";
            string anothera = "alma";
            "alma".Is().Not.SameAs("alma").Should().Be.False();
            a.Is().Not.SameAs(anothera).Should().Be.False();
            a.Is().Not.SameAs(a).Should().Be.False();
            "alma".Is().Not.SameAs("jkrte").Should().Be.True();

            string actual = "Abc";
            string expected = "a".ToUpperInvariant() + "bc";
            actual.Is().Not.SameAs(expected).Should().Be.True();

            ComparableObject c = new ComparableObject(1);
            ComparableObject anotherc = new ComparableObject(1);
            c.Is().Not.SameAs(c).Should().Be.False();
            c.Is().Not.SameAs(anotherc).Should().Be.True();

            object nullObject = null;
            nullObject.Is().Not.SameAs(1).Should().Be.True();
            //1.Is().Not.SameAs(nullObject).Should().Be.True();
            nullObject.Is().Not.SameAs("a").Should().Be.True();
            //"a".Is().Not.SameAs(nullObject).Should().Be.True();
            nullObject.Is().Not.SameAs(c).Should().Be.True();
            //c.Is().Not.SameAs(nullObject).Should().Be.True();
            nullObject.Is().Not.SameAs(nullObject).Should().Be.False();
            c = null;
            nullObject.Is().Not.SameAs(c).Should().Be.False();
            //c.Is().Not.SameAs(nullObject).Should().Be.False();
            anotherc = null;
            anotherc.Is().Not.SameAs(c).Should().Be.False();
            c.Is().Not.SameAs(anotherc).Should().Be.False();
        }

        [TestMethod]
        public void Test_IsType()
        {
            ComparableObject c = new ComparableObject(1);
            c.Is().OfType<ComparableObject>().Should().Be.True();
            c.Is().OfType(typeof(ComparableObject)).Should().Be.True();
            c.Is().OfType<Exception>().Should().Be.False();
            c.Is().OfType(typeof(Exception)).Should().Be.False();

            DerivedComparableObject gc = new DerivedComparableObject(6);
            gc.Is().OfType<DerivedComparableObject>().Should().Be.True();
            gc.Is().OfType(typeof(DerivedComparableObject)).Should().Be.True();
            gc.Is().OfType<ComparableObject>().Should().Be.False();
            gc.Is().OfType(typeof(ComparableObject)).Should().Be.False();

            object nullObject = null;
            nullObject.Is().OfType<ComparableObject>().Should().Be.False();
            nullObject.Is().OfType(typeof(ComparableObject)).Should().Be.False();
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => c.Is().OfType(null));

            ComparableObject nullComparableObject = null;
            nullComparableObject.Is().OfType<ComparableObject>().Should().Be.False();
            nullComparableObject.Is().OfType(typeof(ComparableObject)).Should().Be.False();
        }

        [TestMethod]
        public void Test_IsNotType()
        {
            ComparableObject c = new ComparableObject(1);
            c.Is().Not.OfType<ComparableObject>().Should().Be.False();
            c.Is().Not.OfType(typeof(ComparableObject)).Should().Be.False();
            c.Is().Not.OfType<Exception>().Should().Be.True();
            c.Is().Not.OfType(typeof(Exception)).Should().Be.True();

            DerivedComparableObject gc = new DerivedComparableObject(6);
            gc.Is().Not.OfType<DerivedComparableObject>().Should().Be.False();
            gc.Is().Not.OfType(typeof(DerivedComparableObject)).Should().Be.False();
            gc.Is().Not.OfType<ComparableObject>().Should().Be.True();
            gc.Is().Not.OfType(typeof(ComparableObject)).Should().Be.True();

            object nullObject = null;
            nullObject.Is().Not.OfType<ComparableObject>().Should().Be.True();
            nullObject.Is().Not.OfType(typeof(ComparableObject)).Should().Be.True();
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => c.Is().Not.OfType(null));
        }

        [TestMethod]
        public void Test_IsAssignableFrom()
        {
            ComparableObject c = new ComparableObject(1);
            c.Is().AssignableFrom<ComparableObject>().Should().Be.True();
            c.Is().AssignableFrom(typeof(ComparableObject)).Should().Be.True();
            c.Is().AssignableFrom<IComparable>().Should().Be.True();
            c.Is().AssignableFrom(typeof(IComparable)).Should().Be.True();
            c.Is().AssignableFrom<Exception>().Should().Be.False();
            c.Is().AssignableFrom(typeof(Exception)).Should().Be.False();

            DerivedComparableObject gc = new DerivedComparableObject(6);
            gc.Is().AssignableFrom<DerivedComparableObject>().Should().Be.True();
            gc.Is().AssignableFrom(typeof(DerivedComparableObject)).Should().Be.True();
            gc.Is().AssignableFrom<ComparableObject>().Should().Be.True();
            gc.Is().AssignableFrom(typeof(ComparableObject)).Should().Be.True();
            gc.Is().AssignableFrom<IComparable>().Should().Be.True();
            gc.Is().AssignableFrom(typeof(IComparable)).Should().Be.True();
            gc.Is().AssignableFrom<Exception>().Should().Be.False();
            gc.Is().AssignableFrom(typeof(Exception)).Should().Be.False();

            object nullObject = null;
            nullObject.Is().AssignableFrom<DerivedComparableObject>().Should().Be.False();
            nullObject.Is().AssignableFrom(typeof(DerivedComparableObject)).Should().Be.False();
            Should.Core.Assertions.Assert.Throws<ArgumentNullException>(() => c.Is().AssignableFrom(null));
        }

        [TestMethod]
        public void Test_IsConvertableTo()
        {
            string onestring = "1";
            onestring.Is().ConvertableTo<int>().Should().Be.True();
            onestring.Is().ConvertableTo<bool>().Should().Be.False();

            int oneint = 1;
            oneint.Is().ConvertableTo<bool>().Should().Be.False();

            string nonnumberstring = "alma";
            nonnumberstring.Is().ConvertableTo<int>().Should().Be.False();
            nonnumberstring.Is().ConvertableTo<bool>().Should().Be.False();

            string truestring = "true";
            truestring.Is().ConvertableTo<bool>().Should().Be.True();
            truestring.Is().ConvertableTo<int>().Should().Be.False();
        }

    }
}
